#include "epd_ui.h"
#include "imageHiGeek.h"

/**
 * @brief       在显存中进行画点操作
 * @param       x位置
 * @param	y位置
 * @param	像素点颜色，黑色或者白色。
 * @retval      None
 */
void UI_DrawPixel(uint16_t x, uint16_t y, UI_PixelColor pixelColor)
{
  uint8_t byteBuffer = 0x80 >> x % 8;
  if(pixelColor == UI_PIXEL_BLACK)
  {
    EPD_DisplayBuffer[x / 8 + y * 16] &= ~byteBuffer;
  }
  else
  {
    EPD_DisplayBuffer[x / 8 + y * 16] |= byteBuffer;
  }
}

/**
 * @brief       在显存中进行画线操作
 * @param       起始x坐标
 * @param	起始y坐标
 * @param       结束x坐标
 * @param	结束y坐标
 * @param	像素点颜色，黑色或者白色。
 * @retval      None
 */
void UI_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, UI_PixelColor pixelColor)
{
  uint16_t tmp;
  uint16_t x, y;
  uint16_t dx, dy;
  int16_t err;
  int16_t yStep;

  uint8_t swapxy = 0;

  dx = (x1 > x2) ? (x1 - x2) : (x2 - x1);
  dy = (y1 > y2) ? (y1 - y2) : (y2 - y1);

  if(dy > dx)
  {
    swapxy = 1;
    tmp = dx; dx =dy; dy = tmp;
    tmp = x1; x1 =y1; y1 = tmp;
    tmp = x2; x2 =y2; y2 = tmp;
  }
  if(x1 > x2)
  {
    tmp = x1; x1 =x2; x2 = tmp;
    tmp = y1; y1 =y2; y2 = tmp;
  }
  err = dx >> 1;
  yStep = ( y2 > y1 ) ? 1 : -1;
  y = y1;

  if(x2 == 0xffff)
    x2--;

  for(x = x1; x <= x2; x++)
  {
    if(swapxy == 0)
      UI_DrawPixel(x, y, pixelColor);
    else
      UI_DrawPixel(y, x, pixelColor);

    err -= (uint8_t)dy;
    if(err < 0)
    {
      y += (uint16_t)yStep;
      err += dx;
    }
  }
}

/**
 * @brief       用于快速在显存中绘画横线与竖线，没有浮点操作。
 * @param	X位置
 * @param       Y位置
 * @param	线段长度
 * @param       线段方向，0为横向，1为竖向。
 * @param       线段颜色
 * @retval      None
 */
void UI_DrawHVLine(uint16_t x, uint16_t y, uint16_t len, uint8_t dir, UI_PixelColor pixelColor)
{
  for(uint16_t i = 0; i < len; i++)
  {
    if(dir)
    {
      if(y + i == 296)
        break;
      UI_DrawPixel(x, y + i, pixelColor);
    }
    else
    {
      if(x + i == 128)
        break;
      UI_DrawPixel(x + i, y, pixelColor);
    }
  }
}

/**
 * @brief       用于在显存中绘画实心方块
 * @param	X位置
 * @param       Y位置
 * @param	方块宽
 * @param       方块高
 * @param       方块颜色
 * @retval      None
 */
void UI_DrawBox(uint16_t x, uint16_t y, uint16_t w, uint16_t h, UI_PixelColor pixelColor)
{
  while(h-- != 0)
  {
    UI_DrawHVLine(x, y, w, 0, pixelColor);
    y++;
  }
}

/**
 * @brief       用于在显存中绘画空心方框
 * @param       X位置
 * @param       Y位置
 * @param       方框宽
 * @param       方框高
 * @param       方框颜色
 * @retval      None
 */
void UI_DrawFrame(uint16_t x, uint16_t y, uint16_t w, uint16_t h, UI_PixelColor pixelColor)
{
  UI_DrawHVLine(x, y, w, 0, pixelColor);
  UI_DrawHVLine(x, y + h - 1, w, 0, pixelColor);
  UI_DrawHVLine(x, y, h, 1, pixelColor);
  UI_DrawHVLine(x + w - 1, y, h, 1, pixelColor);

//  uint16_t xtmp = x;
//  if(h > 1)
//  {
//    h -= 2;
//    y++;
//    if(h > 0)
//    {
//      UI_DrawHVLine(x, y, h, 1, pixelColor);
//      x += w - 1;
//      UI_DrawHVLine(x, y, h, 1, pixelColor);
//      y += h;
//    }
//    UI_DrawHVLine(xtmp, y, w, 0, pixelColor);
//  }
}

/**
 * @brief       用于在显存中绘画圆角实心方块
 * @param       X位置
 * @param       Y位置
 * @param       方块宽
 * @param       方块高
 * @param       方块颜色
 * @param       圆角半径
 * @retval      None
 */
void UI_DrawRBox(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t r, UI_PixelColor pixelColor)
{
  //TODO
}

/**
 * @brief       用于在显存中绘画圆角空心方块
 * @param       X位置
 * @param       Y位置
 * @param       方块宽
 * @param       方块高
 * @param       方块颜色
 * @param       圆角半径
 * @retval      None
 */
void UI_DrawRFrame(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t r, UI_PixelColor pixelColor)
{
  //TODO
}

/**
 * @brief       从字库芯片中取出相应的字库数据，并写入显示缓存中。
 * @param       需要显示的ASCII码
 * @param       字体大小
 * @param       x位置
 * @param       y位置
 * @param       字体颜色
 * @retval      None
 */
void UI_DisplayASCII(char ascii, UI_FontType font, uint16_t x, uint16_t y, UI_PixelColor pixelColor)
{
  uint8_t fontBuffer[64];
  uint8_t xEnd, yEnd;
  switch(font)
  {
    case UI_FONT_7:
      xEnd = 8;
      yEnd = 8;
      GT_FontGetASCII7(ascii, fontBuffer);
      break;
    case UI_FONT_8:
      xEnd = 8;
      yEnd = 8;
      GT_FontGetASCII8(ascii, fontBuffer);
      break;
    case UI_FONT_12:
      xEnd = 8;
      yEnd = 12;
      GT_FontGetASCII12(ascii, fontBuffer);
      break;
    case UI_FONT_16:
      xEnd = 8;
      yEnd = 16;
      GT_FontGetASCII16(ascii, fontBuffer);
      break;
    case UI_FONT_24:
      xEnd = 16;
      yEnd = 24;
      GT_FontGetASCII24(ascii, fontBuffer);
      break;
    case UI_FONT_32:
      xEnd = 16;
      yEnd = 32;
      GT_FontGetASCII32(ascii, fontBuffer);
      break;
    default:
      break;
  }
  uint8_t step = xEnd / 8;
  for(uint8_t yTemp = 0; yTemp < yEnd; yTemp++)
  {
    for(uint8_t xTemp = 0; xTemp < xEnd; xTemp++)
    {
      if(fontBuffer[step * yTemp + xTemp / 8] & 0x80 >> xTemp % 8)
      {
        UI_DrawPixel(x + xTemp, y + yTemp, pixelColor);
      }
    }
  }
}

/**
 * @brief       从字库芯片中取出相应的字库数据，并写入显示缓存中。
 * @param       需要显示的GBK码
 * @param       字体大小
 * @param       x位置
 * @param       y位置
 * @param       字体颜色
 * @retval      None
 */
void UI_DisplayGBK(uint16_t gbk, UI_FontType font, uint16_t x, uint16_t y, UI_PixelColor pixelColor)
{
  uint8_t fontBuffer[128];
  uint8_t xEnd, yEnd;
  switch(font)
  {
    case UI_FONT_7:
      xEnd = 8;
      yEnd = 8;
      GT_FontGetASCII7('?', fontBuffer);
      break;
    case UI_FONT_8:
      xEnd = 8;
      yEnd = 8;
      GT_FontGetASCII8('?', fontBuffer);
      break;
    case UI_FONT_12:
      xEnd = 16;
      yEnd = 12;
      GT_FontGetHZ12(gbk, fontBuffer);
      break;
    case UI_FONT_16:
      xEnd = 16;
      yEnd = 16;
      GT_FontGetHZ16(gbk, fontBuffer);
      break;
    case UI_FONT_24:
      xEnd = 24;
      yEnd = 24;
      GT_FontGetHZ24(gbk, fontBuffer);
      break;
    case UI_FONT_32:
      xEnd = 32;
      yEnd = 32;
      GT_FontGetHZ32(gbk, fontBuffer);
      break;
    default:
      break;
  }
  uint8_t step = xEnd / 8;
  for(uint8_t yTemp = 0; yTemp < yEnd; yTemp++)
  {
    for(uint8_t xTemp = 0; xTemp < xEnd; xTemp++)
    {
      if(fontBuffer[step * yTemp + xTemp / 8] & 0x80 >> xTemp % 8)
      {
        UI_DrawPixel(x + xTemp, y + yTemp, pixelColor);
      }
    }
  }
}

/**
 * @brief       用于将字符串映射到现存Buffer中
 * @param       字符串
 * @param       字体
 * @param       X位置
 * @param       Y位置
 * @param       字体颜色
 * @retval      None
 */
void UI_DisplayStringToBuffer(const char* string, UI_FontType font, uint16_t x, uint16_t y, UI_PixelColor pixelColor)
{
  char stringBuffer[20];
  uint8_t stringLen = 0;
  uint8_t xStep;
  switch(font)
  {
    case UI_FONT_7:
      xStep = 6;
      break;
    case UI_FONT_8:
      xStep = 8;
      break;
    case UI_FONT_12:
      xStep = 6;
      break;
    case UI_FONT_16:
      xStep = 8;
      break;
    case UI_FONT_24:
      xStep = 12;
      break;
    case UI_FONT_32:
      xStep = 16;
      break;
    default:
      xStep = 0;
      break;
  }
  memset(stringBuffer, 0, sizeof(stringBuffer));
  stringLen = UTF8_TO_GBK(string, stringBuffer);
  for(uint8_t i = 0; i < stringLen; i++)
  {
    if(stringBuffer[i] < 0x7f)
    {
      UI_DisplayASCII(stringBuffer[i], font, x, y, pixelColor);
      x += xStep;
    }
    else
    {
      uint16_t gbkBuffer;
      gbkBuffer = (uint16_t)stringBuffer[i++] << 8;
      gbkBuffer |= stringBuffer[i];
      UI_DisplayGBK(gbkBuffer, font, x, y, pixelColor);
      x += xStep * 2;
    }
  }
}

/**
 * @brief       立即显示数据到屏幕上
 * @param       字符串指针
 * @param       字体类型
 * @param       x坐标
 * @param       y坐标
 * @retval      None
 */
void UI_DisplayString(const char *str, UI_FontType font, uint8_t x, uint8_t y)
{
  UI_DisplayStringToBuffer(str, font, x, y, UI_PIXEL_BLACK);
  EPD_Refresh();
}

void UI_DisplayImage(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint8_t *image)
{
  uint16_t wTemp = (w + 7) / 8;
  for(uint16_t yTemp = 0; yTemp < h; yTemp++)
  {
    for(uint16_t xTemp = 0; xTemp < w; xTemp++)
    {
      if(image[yTemp * wTemp + xTemp / 8] & 0x80 >> xTemp % 8)
      {
        UI_DrawPixel(x + xTemp, y + yTemp, UI_PIXEL_BLACK);
      }
      else
      {
        UI_DrawPixel(x + xTemp, y + yTemp, UI_PIXEL_WHITE);
      }
    }
  }
}

/**
 * @brief       清理显示缓存数据全为0xff即全白
 * @param       None
 * @retval      None
 */
void UI_ClearScreen(void)
{
  EPD_SetFullBuffer(0xff);
}


void UI_DisplayMainPage(const char* studentID, const char* studentSchool, const char* studentName, const char* message)
{
  UI_ClearScreen();
  UI_DisplayImage(0, 0, 128, 151, gImage_imageHiGeek);
  UI_DisplayStringToBuffer("姓名:", UI_FONT_12, 0, 256, UI_PIXEL_BLACK);
  UI_DisplayStringToBuffer(studentName, UI_FONT_12, 30, 256, UI_PIXEL_BLACK);
  UI_DisplayStringToBuffer("学院:", UI_FONT_12, 0, 270, UI_PIXEL_BLACK);
  UI_DisplayStringToBuffer(studentSchool, UI_FONT_12, 30, 270, UI_PIXEL_BLACK);
  UI_DisplayStringToBuffer("学号:", UI_FONT_12, 0, 284, UI_PIXEL_BLACK);
  UI_DisplayStringToBuffer(studentID, UI_FONT_12, 30, 284, UI_PIXEL_BLACK);
  UI_DisplayStringToBuffer(message, UI_FONT_12, 0, 200, UI_PIXEL_BLACK);
}

void UI_DisplayClassSchedule(ClassScheduleTypeDef* ClassSchedule)
{
  uint16_t yTemp;
  UI_DisplayStringToBuffer(ClassSchedule->week, UI_FONT_24, 28, 0, UI_PIXEL_BLACK);
  UI_DisplayStringToBuffer(ClassSchedule->date, UI_FONT_16, 32, 26, UI_PIXEL_BLACK);
  for(uint8_t i = 0; i < ClassSchedule->classNum; i++)
  {
    yTemp = i * 31 + 48;
    UI_DrawFrame(0, yTemp, 128, 31, UI_PIXEL_BLACK);
    UI_DrawHVLine(1, yTemp + 15, 126, 0, UI_PIXEL_BLACK);
    UI_DrawHVLine(32, yTemp + 1, 14, 1, UI_PIXEL_BLACK);
    UI_DisplayStringToBuffer(ClassSchedule->classInfo[i].time, UI_FONT_12, 2, yTemp + 2, UI_PIXEL_BLACK);
    UI_DisplayStringToBuffer(ClassSchedule->classInfo[i].classRoomName, UI_FONT_12, 34, yTemp + 2, UI_PIXEL_BLACK);
    UI_DisplayStringToBuffer(ClassSchedule->classInfo[i].CourseName, UI_FONT_12, 2, yTemp + 17, UI_PIXEL_BLACK);
  }
}

void UI_DisplayNotice()
{

}
